package com.haidao.admin.component.service.thirdpart.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import com.haidao.admin.component.configuration.CryptoConfiguration;
import com.haidao.admin.component.constants.Constant;
import com.haidao.admin.component.dao.KeyCodeDao;
import com.haidao.admin.component.entity.KeyCodeInfo;
import com.haidao.admin.component.service.thirdpart.CryptoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * `用户操作`加解密服务类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SecondAreaCryptoServiceImpl implements CryptoService {
    private static KeyCodeInfo __cryptoKey;  // 加解密密钥

    private final CryptoConfiguration cryptoConfig;

    private final KeyCodeDao keyCodeDao;

    private final JiDaUtilService jiDaUtilService;


    // 加密
    @Override
    public String encrypt(String str) {
        String keyCode = getKeyCode();
        String encryptUrl = cryptoConfig.getBaseUrl() + cryptoConfig.getEncryptUri();

        Map<String, String> reqHeaders = jiDaUtilService.getReqHeaders();

        Map<String, Object> reqBody = new HashMap<>();
        reqBody.put("keyCode", keyCode);
        reqBody.put("algorithmParam", "SM4/ECB/PKCS7Padding");
        reqBody.put("data", Base64.encode(str));
        JSONObject respBody = jiDaUtilService.sendPostReq(reqHeaders, reqBody, encryptUrl);
        JSONObject data = respBody.getJSONObject("data");
        return data.getStr("encData");
    }

    // 解密
    @Override
    public String decrypt(String str) {
        String keyCode = getKeyCode();
        String encryptUrl = cryptoConfig.getBaseUrl() + cryptoConfig.getDecryptUri();

        Map<String, String> reqHeaders = jiDaUtilService.getReqHeaders();

        Map<String, Object> reqBody = new HashMap<>();
        reqBody.put("keyCode", keyCode);
        reqBody.put("algorithmParam", "SM4/ECB/PKCS7Padding");
        reqBody.put("encData", str);
        JSONObject respBody = jiDaUtilService.sendPostReq(reqHeaders, reqBody, encryptUrl);
        JSONObject data = respBody.getJSONObject("data");
        String base64Data = data.getStr("data");
        return Base64.decodeStr(base64Data);

    }


    /**
     * 获取密钥
     * @return 密钥
     */
    private String getKeyCode() {
        // 0. 内存中存在密钥且未过期则直接返回
        if (__cryptoKey != null && __cryptoKey.getExpirationTime().after(new Date())) {
            log.info("从内存中获取密钥");
            return __cryptoKey.getKeyCode();
        }
        // 1.数据库获取密钥
        KeyCodeInfo dbKeyCodeInfo = keyCodeDao.findByUsage(Constant.CRYPTO);
        if (dbKeyCodeInfo == null) {
            // 2.1.1 没有密钥则从密钥服务器获取密钥
            dbKeyCodeInfo = jiDaUtilService.getKeyCodeFromServer("SM4", 128, "0");
            dbKeyCodeInfo.setUsage(Constant.CRYPTO);
            // 2.1.2保存密钥到数据库
            keyCodeDao.save(dbKeyCodeInfo);
            // 2.1.3保存密钥到内存
            __cryptoKey = dbKeyCodeInfo;
            log.info("从密钥服务器获取密钥");
            return __cryptoKey.getKeyCode();
        }
        // 2.2.1存在秘钥
        __cryptoKey = dbKeyCodeInfo;
        Date expirationTime = __cryptoKey.getExpirationTime();
        int compare = DateUtil.compare(expirationTime, new Date());
        // 2.2.2判断是否过期
        if (compare <= 0) {
            // 2.2.3过期则从密钥服务器延长密钥
            log.info("从密钥服务器延长密钥");
            __cryptoKey = jiDaUtilService.extendKeyCodeExpirationTime(__cryptoKey);
            // 2.2.4更新密钥到数据库
            keyCodeDao.save(__cryptoKey);  // 对象存在id时自动更新
        }
        // 3返回密钥
        return __cryptoKey.getKeyCode();
    }
}
